package vip.xiaonuo.modular.attendancerecord.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import vip.xiaonuo.facedoor.modular.memberuser.entity.MemberUser;
import vip.xiaonuo.modular.attendanceflexrestdays.entity.FlexRestDays;
import vip.xiaonuo.modular.attendanceflexrestdays.service.FlexRestDaysService;
import vip.xiaonuo.modular.attendancegroup.entity.AttendanceGroup;
import vip.xiaonuo.modular.attendancerecord.entity.AttendanceRecord;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class AttendanceFlexSettlementService extends AttendancePlanBaseService{


    @Resource
    private AttendanceRecordService recordService;

    @Resource
    private FlexRestDaysService daysService;

    private final String date_format = "yyyy-MM-dd";

    public void flexRecordSettlementByGroup(AttendanceGroup group){
        // 获取人员
        List<MemberUser> users = super.getMemberUsers(group.getOrgIds());
        if(users == null || users.size() == 0){
            log.info("月度考勤结算异常,考勤组{}内无员工",group.getGroupName());
        }

        Date lastMonth = DateUtil.lastMonth();
        int restDays = getRestDay(group,lastMonth);
        if(ObjectUtil.isEmpty(restDays) || ObjectUtil.equal(restDays,0) || restDays < 0){
            log.info("跳过月度考勤结算,考勤组{}内员工全月无休，直接去劳动局吧",group.getGroupName());
        }

        for(MemberUser user : users){
            this.doHandleFlexRecordSettlementByUser(group,user,lastMonth);
        }
    }

    private int getRestDay(AttendanceGroup group,Date lastMonth){
        if(ObjectUtil.equal(group.getIsFixed(),Boolean.TRUE)){
            return group.getRestDays();
        }else {
            String lastMonth_s = DateUtil.format(lastMonth,"yyyy-MM");
            FlexRestDays restDays = daysService.getOne(new LambdaQueryWrapper<FlexRestDays>()
                    .eq(FlexRestDays :: getAttendanceGroupId , group.getId())
                    .eq(FlexRestDays :: getMonth ,lastMonth_s));
            if(ObjectUtil.isEmpty(restDays)){
                throw new RuntimeException(lastMonth_s + "未设置休息天数，无法进行月度结算");
            }else {
                return restDays.getRestDays();
            }
        }
    }

    private void doHandleFlexRecordSettlementByUser(AttendanceGroup group, MemberUser user, Date lastMonth) {
        Date start =  DateUtil.beginOfMonth(lastMonth);
        Date end = DateUtil.endOfMonth(lastMonth);

        List<AttendanceRecord> records = recordService.list(new LambdaQueryWrapper<AttendanceRecord>()
                .eq(AttendanceRecord :: getAttendanceGroupId , group.getId())
                .eq(AttendanceRecord :: getMemberUserId ,user.getId())
                .gt(AttendanceRecord :: getStartDate , start)
                .lt(AttendanceRecord :: getStartDate , end)
                .orderByAsc(AttendanceRecord :: getStartDate));

        if(ObjectUtil.isEmpty(records)){
            return;
        }

        // 记录出勤的日期
        List<String> dutyDates = new ArrayList<>();
        // 没有打卡时间的考勤记录
        List<AttendanceRecord> notClockInRecords = new ArrayList<>();
        for(AttendanceRecord record : records){
            // 打卡时间不为空，说明出勤了
            if(ObjectUtil.isNotNull(record.getClockInTime()) || ObjectUtil.isNotNull(record.getClockOutTime())){
                String duty_ymd = DateUtil.format(record.getStartDate(),date_format);
                if(!dutyDates.contains(duty_ymd)){
                    dutyDates.add(duty_ymd);
                }
            }else {
                notClockInRecords.add(record);
            }
        }

        // 休息的日期
        List<String> restDates = new ArrayList<>();
        while(start.before(end)){
            String date_ymd = DateUtil.format(start,date_format);
            if(!dutyDates.contains(date_ymd)){
                restDates.add(date_ymd);
            }
            start = DateUtil.offsetDay(start,1);
        }

        List<AttendanceRecord> toRemoveRecord = new ArrayList<>();
        List<AttendanceRecord> toUpdateRecord = new ArrayList<>();
        // 加班天数
        int extra_work_days = group.getRestDays() - restDates.size();

        // 有加班情况，删除休息日期对应的考勤记录
        if(extra_work_days > 0){
            toRemoveRecord = this.removeHolidayRecord(notClockInRecords,restDates);
            dutyDates = dutyDates.subList(dutyDates.size()-extra_work_days, dutyDates.size());
            toUpdateRecord = this.extraDutyRecord(records,dutyDates);
        }else { // 没有情况，删除休息日期对应的考勤记录
            restDates = restDates.subList(0,group.getRestDays()-1);
            toRemoveRecord = this.removeHolidayRecord(notClockInRecords,restDates);
        }

        if(ObjectUtil.isNotEmpty(toRemoveRecord)){
            recordService.removeBatchByIds(toRemoveRecord);
        }

        if(ObjectUtil.isNotEmpty(toUpdateRecord)){
            recordService.saveBatch(toUpdateRecord);
        }
    }

    /**
     *
     * @param notClockInRecords 未打卡记录
     * @param restDates         休息的日期
     * @return
     */
    private List<AttendanceRecord> removeHolidayRecord(List<AttendanceRecord> notClockInRecords, List<String> restDates) {
        List<AttendanceRecord> result = new ArrayList<>();
        for(AttendanceRecord record : notClockInRecords){
            String duty_ymd = DateUtil.format(record.getStartDate(),date_format);
            if(restDates.contains(duty_ymd)){
                result.add(record);
            }
        }
        return result;
    }


    /**
     *
     * @param records           所有的打卡记录
     * @param dutyDates         额外出勤的日期
     * @return
     */
    private List<AttendanceRecord> extraDutyRecord(List<AttendanceRecord> records, List<String> dutyDates) {
        List<AttendanceRecord> result = new ArrayList<>();
        for(AttendanceRecord record : records){
            String duty_ymd = DateUtil.format(record.getStartDate(),date_format);
            if(dutyDates.contains(duty_ymd)){
                record.setIsAddition(1);
                result.add(record);
            }
        }
        return result;
    }

}
